'use strict';
const UUID = require('uuid');
const Service = require('egg').Service;
const _ = require('lodash');
const moment = require('moment');


const USER_TABLE = 'lottery_user';
const AWARD_TABLE = 'lottery_award';
const CONFIG_TABLE = 'lottery_config';
const POOL_TABLE = 'lottery_pool';
const HISTORY_TABLE = 'lottery_history';
const POOL_AWARDS_MODES = [ 'pool_awards_0', 'pool_awards_1', 'pool_awards_2' ];
const CONFIG_KEY = 'cost';
global.IMG_PATH_PREFIX = '/public/img/';
const DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss';

class LotteryService extends Service {
  // 新增用户
  async addUser(user_name, ore_num) {
    const { app } = this;
    try {
      const id = this.getUUID();
      const result = await app.mysql.insert(USER_TABLE, {
        id,
        user_name,
        ore_num,
      }); // 给 lottery_user 用户表，新增一条数据
      return result;
    } catch (error) {
      console.log(error);
      return null;
    }
  }
  // 修改用户
  async editUser(id, user_name, ore_num) {
    const { app } = this;
    try {
      const result = await app.mysql.update(
        USER_TABLE,
        {
          id,
          user_name,
          ore_num,
        },
        {
          where: {
            id,
          },
        }
      );
      return result;
    } catch (error) {
      console.log(error);
      return null;
    }
  }
  // 查询用户
  async user(id) {
    const { app } = this;
    const QUERY_STR = 'user_name, ore_num';
    const sql = `select ${QUERY_STR} from ${USER_TABLE} where id='${id}'`; // 获取 用户名和矿石数 的 sql 语句
    try {
      const result = await app.mysql.query(sql);
      return result[0];
    } catch (error) {
      console.log(error);
      return null;
    }
  }
  // 查询用户历史抽奖记录
  async userHistory(id) {
    const { app } = this;
    const QUERY_STR = 'a.award_name, h.time';
    const sql = `select ${QUERY_STR} from ${HISTORY_TABLE} h left join ${AWARD_TABLE} a on h.award_id=a.award_id where h.user_id='${id}' order by h.time`;
    try {
      const result = await app.mysql.query(sql);
      return result;
    } catch (error) {
      console.log(error);
      return null;
    }
  }
  // 添加一个奖品项目
  async addAward(id, award_name, image_type) {
    const { app } = this;
    try {
      let result;
      let award_id;
      if (id) {
        award_id = id;
        let data;
        if (award_name) {
          data = {
            award_name,
            award_image: global.IMG_PATH_PREFIX + award_id + '.' + image_type,
          };
        } else {
          data = {
            award_image: global.IMG_PATH_PREFIX + award_id + '.' + image_type,
          };
        }
        result = await app.mysql.update(
          AWARD_TABLE,
          data,
          {
            where: {
              award_id,
            },
          }
        );
      } else {
        award_id = this.getUUID();
        result = await app.mysql.insert(AWARD_TABLE, {
          award_id,
          award_name,
          award_image: global.IMG_PATH_PREFIX + award_id + '.' + image_type,
        });
      }
      // 清除全局POOL_AWARDS变量，下次查询这个变量时重新获取
      for (let i = 0; i < POOL_AWARDS_MODES.length; i++) {
        app.data.delete(POOL_AWARDS_MODES[i]);
      }
      return result;
    } catch (error) {
      console.log(error);
      return null;
    }
  }
  // 查询奖池中的奖品
  async poolAwards(mode) {
    const { app } = this;
    if (app.data.get(POOL_AWARDS_MODES[mode])) {
      return app.data.get(POOL_AWARDS_MODES[mode]);
    }
    const QUERY_STR =
      'p.number,p.probability,p.type,a.award_id,a.award_name,a.award_image';
    const sql = `select ${QUERY_STR} from ${POOL_TABLE} p ${
      [ 'left', 'right', 'inner' ][mode]
    } join ${AWARD_TABLE} a on p.award_id=a.award_id`;
    try {
      const result = await app.mysql.query(sql);
      app.data.set(POOL_AWARDS_MODES[mode], result);
      return result;
    } catch (error) {
      console.log(error);
      return null;
    }
  }
  // 查询配置，如每次抽奖花费矿石数
  async getConfig() {
    const { app } = this;
    if (app.data.get(CONFIG_KEY)) {
      return app.data.get(CONFIG_KEY);
    }
    const QUERY_STR = 'cost';
    const sql = `select ${QUERY_STR} from ${CONFIG_TABLE}`; // 获取 用户名和矿石数 的 sql 语句
    try {
      const result = await app.mysql.query(sql);
      const config = result[0];
      app.data.set(CONFIG_KEY, config);
      return config;
    } catch (error) {
      console.log(error);
      return null;
    }
  }

  // 抽奖
  async draw(userId) {
    const { app } = this;
    const poolAwards = await this.poolAwards(2);
    let sum = 0;
    // 1 求所有可能的总和，从1开始。如果一个奖品可能性为1，总和为1，表示100%中奖
    for (let i = 0; i < poolAwards.length; i++) {
      sum += poolAwards[i].probability;
    }
    // 2 在这个总和之间产生一个随机数
    let number = _.random(1, sum);
    // 3 随机数落在哪个区间上，就是哪个奖品中奖了
    let res = -1;
    for (let i = 0; i < poolAwards.length; i++) {
      const probability = poolAwards[i].probability;
      if (probability < number) {
        number = number - probability;
      } else {
        res = i;
        break;
      }
    }
    // 给前端抽奖页的数据，去掉 probability 的字段
    const data = {};
    _.assign(data, poolAwards[res]);
    delete data.probability;
    // 4 修改 用户表，用户的矿石数
    try {
      const user = await this.user(userId);
      const config = await this.getConfig();
      await this.editUser(
        userId,
        user.user_name,
        user.ore_num -
          config.cost +
          (data.type === 3 ? parseInt(data.award_name) : 0)
      );
      // 5 将本次抽奖结果记录到 历史表中
      await app.mysql.insert(HISTORY_TABLE, {
        user_id: userId,
        award_id: data.award_id,
        time: moment().format(DATE_FORMAT),
      });
    } catch (error) {
      console.log(error);
    }
    return data;
  }

  // 设置奖池中的奖品
  async editPool(number, award_id, award_name, award_image, probability, type) {
    const { app } = this;
    let QUERY_STR = 'number';
    let sql = `select ${QUERY_STR} from ${POOL_TABLE} where award_id='${award_id}'`;
    let oldNumber = number;
    try {
      const result = await app.mysql.query(sql);
      if (result.length > 0) {
        oldNumber = result[0][QUERY_STR];
      }
      // 如果修改了当前奖品的奖池号码，就将原奖池号码对应的奖品id清空掉
      if (oldNumber !== number) {
        await app.mysql.query(`update ${POOL_TABLE} set award_id = null where number = ?`, [ oldNumber ]);
      }
    } catch (error) {
      console.log(error);
      return null;
    }
    QUERY_STR = 'number';
    sql = `select ${QUERY_STR} from ${POOL_TABLE} where number=${number}`;
    try {
      let result = await app.mysql.query(sql);
      if (result.length > 0) {
        // 表示存在这条数据，则修改
        result = await app.mysql.update(
          POOL_TABLE,
          {
            number,
            award_id,
            probability,
            type,
          },
          {
            where: {
              number,
            },
          }
        );
      } else {
        result = await app.mysql.insert(POOL_TABLE, {
          number,
          award_id,
          probability,
          type,
        });
      }
      const award_imageArr = award_image.split('.');
      this.addAward(award_id, award_name, award_imageArr[award_imageArr.length - 1]);
      return result;
    } catch (error) {
      console.log(error);
      return null;
    }
  }
  // 修改抽奖消耗矿石数
  async editCost(cost) {
    const { app } = this;
    try {
      const result = await app.mysql.query(`update ${CONFIG_TABLE} set cost = ${cost}`);
      app.data.delete(CONFIG_KEY);
      return result;
    } catch (error) {
      console.log(error);
      return null;
    }
  }
  // 生成uuid
  getUUID() {
    return UUID.v1().replace(/-/g, '');
  }
}
module.exports = LotteryService;
